package br.usjt.component.login.dao;

import java.util.Collections;
import java.util.List;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaQuery;

import org.hibernate.exception.ConstraintViolationException;

import br.com.usjt.component.commons.login.exceptions.DuplicateRegistrationException;
import br.usjt.component.login.facade.dao.GenericDao;
import br.usjt.component.login.model.AbstractEntity;

public abstract class GenericDaoImp<T extends AbstractEntity<?>> implements GenericDao<T> {

    private static final long serialVersionUID = -154856176363946852L;

    @Inject
    private EntityManager em;

    protected Class<T> classe;

    public GenericDaoImp(final Class<T> t) {
        this.classe = t;
    }

    @Override
    public void save(final T t) {

        try {
            getEM().persist(t);
            getEM().flush();

        } catch (PersistenceException e) {
            Throwable th = e.getCause();

            if (th instanceof ConstraintViolationException) {
                throw new DuplicateRegistrationException(th.getCause().getMessage(), e);
            }
        }

    }

    @Override
    public void delete(final T t) {
        getEM().remove(t);
        getEM().flush();

    }

    @Override
    public List<T> findByAll() {
        CriteriaQuery<T> query = getEM().getCriteriaBuilder().createQuery(classe);
        query.from(classe);

        List<T> resultList = getEM().createQuery(query).getResultList();

        if (resultList.isEmpty()) {
            return Collections.emptyList();
        }
        return resultList;
    }

    @Override
    public void update(final T t) {

        try {
            getEM().merge(t);
            getEM().flush();

        } catch (PersistenceException e) {
            Throwable th = e.getCause();

            if (th instanceof ConstraintViolationException) {
                throw new DuplicateRegistrationException(th.getCause().getMessage(), e);
            }

        }

    }

    public List<T> findWithNamedQuery(final String namedQueryName) {
        return getEM().createNamedQuery(namedQueryName, classe).getResultList();
    }

    public int countTotalRecord(final String namedQueryName) {
        Query query = getEM().createNamedQuery(namedQueryName);
        Number result = (Number) query.getSingleResult();
        return result.intValue();
    }

    public List<T> findWithNamedQuery(final String queryName, final int resultLimit) {
        return this.em.createNamedQuery(queryName, classe).setMaxResults(resultLimit).getResultList();
    }

    @Override
    public T findById(final Integer id) {
        return getEM().find(classe, id);
    }

    protected EntityManager getEM() {
        return em;
    }

    protected void setEM(EntityManager em) {
        this.em = em;
    }
}
